﻿//-----------------------------------------------------------------------
// <copyright file="ShelveUnshelve.cs" company="Microsoft Corporation">
//     Copyright (c) Microsoft Corporation 2011. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

namespace Internal.TeamFoundationServer.Submit
{
    using System;
    using System.Diagnostics;
    using System.Drawing;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Windows.Forms;
    using Microsoft.TeamFoundation;
    using Microsoft.TeamFoundation.VersionControl.Client;
    using Properties;

    /// <summary>
    /// Shelve Un-shelve class.
    /// </summary>
    internal partial class ShelveUnshelve : WizardControlTemplate
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ShelveUnshelve"/> class.
        /// </summary>
        public ShelveUnshelve()
        {
             try
            {
                Cursor.Current = Cursors.WaitCursor;
                
                this.InitializeComponent();
                this.textOwner.Text = string.Format(CultureInfo.InvariantCulture, @"{0}\{1}", Environment.UserDomainName, Environment.UserName);

                this.cmbTFSServer.Items.Clear();
                foreach (var item in TeamFoundationHelper.GetRegisteredCollectionNames())
                {
                    this.cmbTFSServer.Items.Add(item);
                }

                Utilities.FixComboItemsWidth(this, this.cmbTFSServer);

                if (this.cmbTFSServer.Items.Count > 0)
                {
                    Utilities.GetDefaultValue(this.cmbTFSServer, Settings.Default.TfsSourceServer);
                }
            }
            finally
            {
                Cursor.Current = Cursors.Default;
            }
        }

        /// <summary>
        /// Update window.
        /// </summary>
        /// <param name="title">Window Title.</param>
        /// <param name="description">Window Description.</param>
        /// <param name="backButtonEnabled">Back Button Enabled?</param>
        /// <param name="nextButtonEnabled">Next Button Enabled?</param>
        /// <param name="nextButtonCaption">Next Button Caption.</param>
        /// <param name="action">Action to perform on control.</param>
        public override void UpdateWindow(Label title, RichTextBox description, out bool backButtonEnabled, out bool nextButtonEnabled, out string nextButtonCaption, object action)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;

                backButtonEnabled = true;
                nextButtonCaption = Resources.UnShelveButtonCaption;
                nextButtonEnabled = this.gridFiles.SelectedRows.Count > 0;

                title.Text = Resources.UnShelveTitle;
                description.Text = Resources.UnhelveDescription;
            }
            finally
            {
                Cursor.Current = Cursors.Default;
            }
        }

        /// <summary>
        /// Button next event.
        /// </summary>
        public override void NextStep()
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;

                if (!this.InternalValidate())
                {
                    return;
                }

                var workspace = TeamFoundationHelper.GetWorkspace(this.cmbTFSServer.Text, this.cmbWorkspace.Text);

                foreach (DataGridViewRow row in this.gridFiles.Rows)
                {
                    if (bool.Parse(row.Cells["colSelect"].Value.ToString()))
                    {
                        var pendingChange = row.Cells["colItem"].Value as PendingChange;
                        if (pendingChange != null)
                        {
                            var localChange = workspace.GetPendingChanges(pendingChange.ServerItem, RecursionType.None);
                            if (localChange != null && localChange.Length > 0)
                            {
                                var localItem = workspace.GetLocalItemForServerItem(pendingChange.ServerItem);
                                if (!string.IsNullOrEmpty(localItem) && !File.Exists(localItem))
                                {
                                    try
                                    {
                                        pendingChange.DownloadShelvedFile(localItem);
                                        row.Cells["colStatus"].Value = "Un-shelved";
                                        row.DefaultCellStyle.BackColor = Color.LightGreen;
                                        continue;
                                    }
                                    catch (InvalidOperationException err)
                                    {
                                        row.Cells["colStatus"].Value = err.Message;
                                        row.DefaultCellStyle.BackColor = Color.Red;
                                    }
                                }
                            }

                            try
                            {
                                workspace.Unshelve(
                                    this.gridShelveSets.SelectedRows[0].Cells["colShelveSet"].Value as string,
                                    this.gridShelveSets.SelectedRows[0].Cells["colOwner"].Value as string,
                                    new[] { new ItemSpec(pendingChange) });

                                row.Cells["colStatus"].Value = "Un-shelved";
                                row.DefaultCellStyle.BackColor = Color.LightGreen;
                            }
                            catch (UnshelveException err)
                            {
                                row.Cells["colStatus"].Value = string.Format(CultureInfo.InvariantCulture, Resources.UshelveErrorString, err.Message, pendingChange.ServerItem);
                                row.DefaultCellStyle.BackColor = Color.Red;
                            }
                        }
                    }
                }

                MessageBox.Show(
                    Resources.UnshelveFinished,
                    Resources.WarningString,
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Warning,
                    MessageBoxDefaultButton.Button1,
                    MessageBoxOptions.RightAlign & MessageBoxOptions.RtlReading);
            }
            finally
            {
                Cursor.Current = Cursors.Default;
            }
        }

        /// <summary>
        /// Internal Validate.
        /// </summary>
        /// <returns>False if has errors, otherwise true.</returns>
        private bool InternalValidate()
        {
            if (this.cmbWorkspace.Text.Length == 0)
            {
                MessageBox.Show(
                    Resources.SelectWorkspaceToUnshelveString,
                    Resources.WarningString,
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Warning,
                    MessageBoxDefaultButton.Button1,
                    MessageBoxOptions.RightAlign & MessageBoxOptions.RtlReading);

                return false;
            }

            if (this.gridFiles.Rows.Cast<DataGridViewRow>().Any(row => bool.Parse(row.Cells["colSelect"].Value.ToString())))
            {
                return true;
            }

            MessageBox.Show(
                   Resources.SelectFilesToUnShelveString,
                   Resources.WarningString,
                   MessageBoxButtons.OK,
                   MessageBoxIcon.Warning,
                   MessageBoxDefaultButton.Button1,
                   MessageBoxOptions.RightAlign & MessageBoxOptions.RtlReading);
            
            return false;
        }

        /// <summary>
        /// Select TFS Collection.
        /// </summary>
        /// <param name="sender">Object sender.</param>
        /// <param name="e">Event arguments object.</param>
        private void CmbTfsServerSelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;

                this.cmbWorkspace.Items.Clear();
                this.gridShelveSets.Rows.Clear();
                this.gridFiles.Rows.Clear();

                if (this.cmbTFSServer.Text.Length == 0)
                {
                    return;
                }

                Utilities.SetDefaultValue("TfsSourceServer", this.cmbTFSServer.Text);

                // Retrieve User workspaces for specific project collection.
                foreach (var item in TeamFoundationHelper.GetWorkspaceNames(this.cmbTFSServer.Text))
                {
                    this.cmbWorkspace.Items.Add(item);
                }

                Utilities.FixComboItemsWidth(this, this.cmbWorkspace);

                var shelvesets = TeamFoundationHelper.GetShelvesetsByOwner(this.cmbTFSServer.Text, this.textOwner.Text);
                if (shelvesets != null)
                {
                    foreach (var shelveset in shelvesets)
                    {
                        int rowIndex = this.gridShelveSets.Rows.Add();
                        this.gridShelveSets.Rows[rowIndex].Cells["colShelveSet"].Value = shelveset.Name;
                        this.gridShelveSets.Rows[rowIndex].Cells["colDescription"].Value = shelveset.Comment;
                        this.gridShelveSets.Rows[rowIndex].Cells["colOwner"].Value = shelveset.OwnerName;
                        this.gridShelveSets.Rows[rowIndex].Cells["colDate"].Value = shelveset.CreationDate;
                    }
                }
            }
            catch (TeamFoundationServiceUnavailableException err)
            {
                MessageBox.Show(
                   err.Message,
                   Resources.UnhandledException,
                   MessageBoxButtons.OK,
                   MessageBoxIcon.Error,
                   MessageBoxDefaultButton.Button1,
                   MessageBoxOptions.RightAlign & MessageBoxOptions.RtlReading);
            }
            finally
            {
                Cursor.Current = Cursors.Default;
            }
        }

        /// <summary>
        /// TextOwnerKeyPress event.
        /// </summary>
        /// <param name="sender">Object sender.</param>
        /// <param name="e">Event arguments object.</param>
        private void TextOwnerKeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)Keys.Enter)
            {
                this.CmbTfsServerSelectedIndexChanged(sender, null);
            }
        }

        /// <summary>
        /// GridShelveSetsSelectionChanged event.
        /// </summary>
        /// <param name="sender">Object sender.</param>
        /// <param name="e">Event arguments object.</param>
        private void GridShelveSetsSelectionChanged(object sender, EventArgs e)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;

                this.chkRows.Checked = false;
                this.gridFiles.Rows.Clear();

                if (this.gridShelveSets.SelectedRows.Count != 1)
                {
                    return;
                }

                // Get shelve set object
                var shelvesets = TeamFoundationHelper.GetShelvesetsByOwner(this.cmbTFSServer.Text, this.textOwner.Text, this.gridShelveSets.SelectedRows[0].Cells["colShelveSet"].Value as string);
                var pendingChanges = TeamFoundationHelper.GetPendingChangesByShelveSet(shelvesets[0]);
                foreach (var pendingChange in pendingChanges)
                {
                    this.gridFiles.Rows.Add(false, pendingChange.FileName, pendingChange.ServerItem, string.Empty, pendingChange);
                }
            }
            finally
            {
                this.FireChangeContinueButtonEnabled(this.gridFiles.Rows.Count > 0);

                Cursor.Current = Cursors.Default;
            }
        }

        /// <summary>
        /// Open Item.
        /// </summary>
        private void OpenItem()
        {
            var pendingChange = this.gridFiles.SelectedRows[0].Cells["colItem"].Value as PendingChange;
            if (pendingChange != null)
            {
                var shelveFileName = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\" + pendingChange.FileName + ".shelve.temp";
                pendingChange.DownloadShelvedFile(shelveFileName);
                using (var process = new Process())
                {
                    process.StartInfo.FileName = "notepad.exe";
                    process.StartInfo.Arguments = shelveFileName;
                    process.StartInfo.UseShellExecute = false;
                    process.StartInfo.RedirectStandardOutput = true;
                    process.StartInfo.CreateNoWindow = true;
                    process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

                    if (process.Start())
                    {
                        process.WaitForExit(1000);
                        File.Delete(shelveFileName);
                    }
                }
            }
        }

        /// <summary>
        /// Compare Shelve Item Against Server Item.
        /// </summary>
        private void CompareShelveItemAgainstServerItem()
        {
            var pendingChange = this.gridFiles.SelectedRows[0].Cells["colItem"].Value as PendingChange;
            if (pendingChange != null)
            {
                var shelveFileName = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\" + pendingChange.FileName + ".shelve.temp";
                pendingChange.DownloadShelvedFile(shelveFileName);

                var serverFileName = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\" + pendingChange.FileName + ".server.temp";
                if (!pendingChange.VersionControlServer.ServerItemExists(pendingChange.ServerItem, pendingChange.ItemType))
                {
                    MessageBox.Show(
                        Resources.NoFileServerVersionString,
                        Resources.WarningString,
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Warning,
                        MessageBoxDefaultButton.Button1,
                        MessageBoxOptions.RightAlign & MessageBoxOptions.RtlReading);
                }

                pendingChange.VersionControlServer.DownloadFile(pendingChange.ServerItem, serverFileName);
                using (var process = new Process())
                {
                    process.StartInfo.FileName = "diffmerge.exe";
                    process.StartInfo.Arguments = string.Format(CultureInfo.InvariantCulture, "\"{0}\" \"{1}\" /ignorespace", serverFileName, shelveFileName);
                    process.StartInfo.UseShellExecute = false;
                    process.StartInfo.RedirectStandardOutput = true;
                    process.StartInfo.CreateNoWindow = true;
                    process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

                    if (process.Start())
                    {
                        process.WaitForExit(1000);
                        File.Delete(shelveFileName);
                        File.Delete(serverFileName);
                    }
                }
            }
        }

        /// <summary>
        /// Compare Shelve Item Against Local Item.
        /// </summary>
        private void CompareShelveItemAgainstLocalItem()
        {
            if (this.cmbWorkspace.Text.Length == 0)
            {
                MessageBox.Show(
                    Resources.SelectWorkspaceToUnshelveString,
                    Resources.WarningString,
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Warning,
                    MessageBoxDefaultButton.Button1,
                    MessageBoxOptions.RightAlign & MessageBoxOptions.RtlReading);
                return;
            }

            var workspace = TeamFoundationHelper.GetWorkspace(this.cmbTFSServer.Text, this.cmbWorkspace.Text);
            var pendingChange = this.gridFiles.SelectedRows[0].Cells["colItem"].Value as PendingChange;
            if (pendingChange != null)
            {
                var localFileName = workspace.GetLocalItemForServerItem(pendingChange.ServerItem);

                var shelveFileName = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\" + pendingChange.FileName + ".shelve.temp";
                pendingChange.DownloadShelvedFile(shelveFileName);

                using (var process = new Process())
                {
                    process.StartInfo.FileName = "diffmerge.exe";
                    process.StartInfo.Arguments = string.Format(CultureInfo.InvariantCulture, "\"{0}\" \"{1}\" /ignorespace", shelveFileName, localFileName);
                    process.StartInfo.UseShellExecute = false;
                    process.StartInfo.RedirectStandardOutput = true;
                    process.StartInfo.CreateNoWindow = true;
                    process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

                    if (process.Start())
                    {
                        process.WaitForExit(1000);
                        File.Delete(shelveFileName);
                    }
                }
            }
        }

        /// <summary>
        /// GridFilesDoubleClick event.
        /// </summary>
        /// <param name="sender">Object sender.</param>
        /// <param name="e">Event arguments object.</param>
        private void GridFilesDoubleClick(object sender, EventArgs e)
        {
            if (this.gridFiles.SelectedRows.Count != 1)
            {
                return;
            }

            this.OpenItem();
        }

        /// <summary>
        /// Header click event.
        /// </summary>
        /// <param name="sender">Object sender.</param>
        /// <param name="e">Event arguments object.</param>
        private void ChkRowsCheckedChanged(object sender, EventArgs e)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;

                // We use this code to mark/unmark all files as selected/unselected. 
                var dataGridViewColumn = this.gridFiles.Columns["colSelect"];
                if (dataGridViewColumn != null)
                {
                    bool selected = this.chkRows.Checked;
                    for (var index = this.gridFiles.Rows.Count - 1; index >= 0; index--)
                    {
                        this.gridFiles.Rows[index].Cells["colSelect"].Value = selected;
                    }
                }
            }
            finally
            {
                Cursor.Current = Cursors.Default;
            }
        }

        /// <summary>
        /// Grid Header column width changed event.
        /// </summary>
        /// <param name="sender">Object sender.</param>
        /// <param name="e">Event arguments object.</param>
        private void GridFilesColumnWidthChanged(object sender, DataGridViewColumnEventArgs e)
        {
            if (e.Column == this.gridFiles.Columns["colSelect"])
            {
                Debug.Assert(e.Column != null, "Column should never be null");
                e.Column.Width = 50;
            }
        }

        /// <summary>
        /// GridFilesMouseClick event.
        /// </summary>
        /// <param name="sender">Object sender.</param>
        /// <param name="e">Event arguments object.</param>
        private void GridFilesMouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right && this.gridFiles.SelectedRows.Count > 0)
            {
                this.menuFiles.Show(Cursor.Position.X, Cursor.Position.Y);
            }
        }

        /// <summary>
        /// MenuViewClick event.
        /// </summary>
        /// <param name="sender">Object sender.</param>
        /// <param name="e">Event arguments object.</param>
        private void MenuViewClick(object sender, EventArgs e)
        {
            this.OpenItem();
        }

        /// <summary>
        /// MenuCompareServerClick event.
        /// </summary>
        /// <param name="sender">Object sender.</param>
        /// <param name="e">Event arguments object.</param>
        private void MenuCompareServerClick(object sender, EventArgs e)
        {
            this.CompareShelveItemAgainstServerItem();
        }

        /// <summary>
        /// MenuCompareLocalClick event.
        /// </summary>
        /// <param name="sender">Object sender.</param>
        /// <param name="e">Event arguments object.</param>
        private void MenuCompareLocalClick(object sender, EventArgs e)
        {
            this.CompareShelveItemAgainstLocalItem();
        }
    }
}
